// Copyright (c) 2021 Presto Labs Pte. Ltd.
// Author: hyuan

#pragma once

#include <memory>
#include <set>
#include <string>
#include <utility>

#include "coin/proto/coin_order_enums.pb.h"
#include "coin2/exchange/base/api_base/asio_http_context.h"
#include "coin2/exchange/base/order/parser.h"
#include "coin2/exchange/kucoin/api_util/rate_tracker.h"
#include "coin2/exchange/kucoin_futures/symbology/product.h"

namespace coin2::exchange::kucoin_futures::order_v1 {

class KucoinFuturesParser : public base::order::BaseParser {
  using JsonValue = base::order::BaseParser::JsonValue;
  using SubmitOrderResponse = base::order::BaseParser::SubmitOrderResponse;
  using ProductOrderBundle = base::order::BaseParser::ProductOrderBundle;
  using ProductFillBundle = base::order::BaseParser::ProductFillBundle;
  using AccountBalance = base::order::BaseParser::AccountBalance;
  using ProductOrderElement = base::order::BaseParser::ProductOrderElement;
  using ProductFillElement = base::order::BaseParser::ProductFillElement;
  using AccountPosition = base::order::BaseParser::AccountPosition;
  using OrderErrorCode = base::order::BaseParser::OrderErrorCode;
  using OrderSubTopicId = base::order::BaseParser::OrderSubTopicId;
  using OrderSide = coin::proto::OrderSide;
  using OrderType = coin::proto::OrderType;
  using CurrencyPairs = std::set<std::pair<std::string, std::string>>;
  using RateLimitInfo = coin2::exchange::kucoin::api_util::RateLimitInfo;

 public:
  const ParseResult& ParseRawMessage(const RawMessage& msg) override;
  AccountBalance ParseBalance(const JsonValue& doc) override;
  AccountPosition ParsePosition(const JsonValue& doc) override;
  bool ParseRawPosition(const JsonValue& doc, RawPositionMap* raw_position_map);

 private:
  void ParseRestAccountBalance();
  void ParseRestAccountPosition();
  void ParseRestOpenOrderInfoList();
  void ParseRestHistOrderInfoList();
  void ParseRestFillInfoList();
  void ParseRestBullet();
  void ParseSubmitResponse();
  void ParseCancelResponse();

  void ParseWsOrderInfoList(const JsonDocument& document);
  void ParseWsTradeInfoList(const JsonDocument& document);
  void ParseWsBalanceInfoList(const JsonDocument& document);
  void ParseWsPositionInfoList(const JsonDocument& document);
  void ParseWsMessage();

  void ParseRestOrderInfo(const JsonValue& data, ProductOrderElement* order);
  void ParseRestFillInfo(const JsonValue& data, ProductFillElement* fill);

  int32_t ParseErrorMessage(const std::shared_ptr<AsioHttpContext>& http_context);

  void SaveBalanceToCacheMap(const JsonValue& doc);
  void GetBalanceFromCacheMap(AccountBalance& acc_balance);

  auto GetNativeCurrencies() const -> std::set<std::string> {
    static const std::set<std::string> currencies = [this]() {
      std::set<std::string> currencies;
      for (const auto* curr : symcache_->GetCurrencies()) {
        currencies.emplace(curr->native_currency());
      }
      return currencies;
    }();
    return currencies;
  }

 private:
  RateLimitInfo enable_time_{0};
  bool is_bullet_initialized_{false};
  RawBalanceMap balance_cache_map_;
  bool is_account_balance_initialized_{false};
  bool is_account_position_initialized_{false};
};

}  // namespace coin2::exchange::kucoin_futures::order_v1
